#include "netclient.h"

#include "../model/datacenter.h"
#include "gateway.qpb.h"
#include "user.qpb.h"
#include "friend.qpb.h"
#include "file.qpb.h"
#include "message_storage.qpb.h"
#include "message_transmit.qpb.h"
#include "speech_recognition.qpb.h"

#include <QLabel>

namespace network {

NetClient::NetClient(model::DataCenter *dataCenter) : m_dataCenter(dataCenter)
{}

void NetClient::ping()
{
    QNetworkRequest httpReq;
    httpReq.setUrl(QUrl(HTTP_URL + "/ping"));

    QNetworkReply* httpResp = m_httpClient.get(httpReq);
    connect(httpResp, &QNetworkReply::finished, this, [=]{
        if(httpResp->error() != QNetworkReply::NoError){
            LOG() << "请求失败" << httpResp->errorString();
            httpResp->deleteLater();
            return ;
        }

        QByteArray body = httpResp->readAll();
        httpResp->deleteLater();
        LOG() << "请求成功！响应内容：" << body;
    });

}

////////////////////////////////////////////////
/// 下列都是 WebSocket服务 的操作
////////////////////////////////////////////////

void NetClient::initWebsocket()
{
    connect(&m_websocketClient, &QWebSocket::connected, this, [=]{
        LOG() << "webSocket 连接成功！";
        // 建立长连接之后，发送身份认证
        sendAuthentication();
    });
    connect(&m_websocketClient, &QWebSocket::disconnected, this, [=]{
        LOG() << "webSocket 断开连接！";
    });
    connect(&m_websocketClient, &QWebSocket::errorOccurred, this, [=](QAbstractSocket::SocketError error){
        LOG() << "webSocket 连接错误：" << error;
    });
    connect(&m_websocketClient, &QWebSocket::textMessageReceived, this, [=](const QString& msg){
        LOG() << "webSocket 收到文本数据：" << msg;
    });
    connect(&m_websocketClient, &QWebSocket::binaryMessageReceived, this, [=](const QByteArray& data){
        LOG() << "webSocket 收到二进制数据：" << data.length();
        im::NotifyMessage notifyMsg;
        notifyMsg.deserialize(&m_serializer, data);
        handleWsResponse(notifyMsg);
    });

    // 建立 websocket 连接
    m_websocketClient.open(WEBSOCKET_URL);
}

void NetClient::sendAuthentication()
{
    im::ClientAuthenticationReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(m_dataCenter->getLoginSessionId());
    QByteArray body = req.serialize(&m_serializer);
    m_websocketClient.sendBinaryMessage(body);
    LOG() << "[WS身份认证] requestId=" << req.requestId() << ", loginSessionId=" << req.sessionId();
}

void NetClient::handleWsResponse(const im::NotifyMessage &notifyMsg)
{
    if(notifyMsg.notifyType() == im::NotifyTypeGadget::FRIEND_ADD_APPLY_NOTIFY){
        // 好友申请通知
        im::NotifyFriendAddApply friendAddApply = notifyMsg.friendAddApply();
        model::UserInfo userInfo;
        userInfo.load(friendAddApply.userInfo());
        handleWsAddFriendApplyReq(userInfo);
    }else if(notifyMsg.notifyType() == im::NotifyTypeGadget::FRIEND_ADD_PROCESS_NOTIFY){
        // 好友申请的处理结果通知
        im::NotifyFriendAddProcess addProcess = notifyMsg.friendProcessResult();
        model::UserInfo userInfo;
        userInfo.load(addProcess.userInfo());
        handleWsAddFriendResp(userInfo, addProcess.agree());
    }else if(notifyMsg.notifyType() == im::NotifyTypeGadget::CHAT_SESSION_CREATE_NOTIFY){
        // 创建新会话的通知
        im::NotifyNewChatSession notifyChatSession = notifyMsg.newChatSessionInfo();
        model::chatSessionInfo chatSession;
        chatSession.load(notifyChatSession.chatSessionInfo());
        handleWsSessionCreate(chatSession);
    }else if(notifyMsg.notifyType() == im::NotifyTypeGadget::CHAT_MESSAGE_NOTIFY){
        // 接收到新消息通知
        im::NotifyNewMessage newMsg = notifyMsg.newMessageInfo();
        model::Message msg;
        msg.load(newMsg.messageInfo());
        handleWsMessage(msg);
    }else if(notifyMsg.notifyType() == im::NotifyTypeGadget::FRIEND_REMOVE_NOTIFY){
        // 好友删除通知
        im::NotifyFriendRemove removeMsg = notifyMsg.friendRemove();
        handleWsRemoveFriend(removeMsg.userId());
    }else{
        LOG() << "Websocket接收到“未知类型”";
    }
}

void NetClient::handleWsMessage(const model::Message& msg)
{
    // 初始化其他人发送消息对应的会话的聊天信息缓存
    if(m_dataCenter->getRecentMsgList(msg.m_chatSessionId) == nullptr){
        connect(m_dataCenter, &model::DataCenter::getRecentMsgListDoneNoUI,
                m_dataCenter, &model::DataCenter::receiveMessage, Qt::UniqueConnection);
        m_dataCenter->getRecentMsgListAsync(msg.m_chatSessionId, false);
    }else{
    // 聊天信息缓存已存在，则添加信息即可
        m_dataCenter->addMessage(msg);
        m_dataCenter->receiveMessage(msg.m_chatSessionId);
    }
}

void NetClient::handleWsRemoveFriend(const QString& userID)
{
    LOG() << "处理好友删除，好友ID：" << userID;
    // 服务器告知客⼾端, 某个好友把你删了.
    m_dataCenter->removeFriend(userID);
    emit m_dataCenter->deleteFriendDone();
}

void NetClient::handleWsAddFriendApplyReq(const model::UserInfo& userInfo)
{
    // 头插一个好友申请
    QList<model::UserInfo>* applyList = m_dataCenter->getApplyList();
    if (applyList == nullptr) {
        LOG() << "本地不存在 applyList";
        return;
    }
    // 头插前做一个检查，针对同一个好友我们只生成一个申请好友的对象
    for(auto& f : *applyList){
        if(f.m_userId == userInfo.m_userId){
            LOG() << "好友已经提交申请";
            return ;
        }
    }
    LOG() << "收到好友申请，好友ID：" << userInfo.m_userId << "昵称：" << userInfo.m_nickName;
    applyList->push_front(userInfo);
    emit m_dataCenter->receiveFriendApplyDone();
}

void NetClient::handleWsAddFriendResp(const model::UserInfo& userInfo, bool agree)
{
    // 若成功添加，则1.更新好友缓存 2.更新好友界面
    if(agree){
        LOG() << "同意好友申请，好友ID：" << userInfo.m_userId << "昵称：" << userInfo.m_nickName;
        m_dataCenter->getFriendList()->push_front(userInfo);
        emit m_dataCenter->receiveFriendProcessAccept();
    }else{
        LOG() << "拒绝好友申请，好友ID：" << userInfo.m_userId << "昵称：" << userInfo.m_nickName;
    }
}

void NetClient::handleWsSessionCreate(const model::chatSessionInfo& chatSession)
{
    // 添加会话信息
    auto chatSessionList = m_dataCenter->getChatSessionList();
    if(chatSessionList == nullptr){
        LOG() << "会话内容为空";
        return ;
    }
    LOG() << "收到创建会话请求，会话ID:" << chatSession.m_chatSessionId << "会话名称:" << chatSession.m_userId;
    chatSessionList->push_front(chatSession);
    emit m_dataCenter->receiveSessionCreateDone();
}
////////////////////////////////////////////////
/// 下列都是 http服务 的操作
////////////////////////////////////////////////

void NetClient::getMyself(const QString &loginSessionId)
{
    // 1.构建 个人信息数据 对象的body
    im::GetUserInfoReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    QByteArray body = req.serialize(&m_serializer);

    // 2.构建 http请求
    QNetworkRequest httpReq;
    httpReq.setUrl(QUrl(HTTP_URL + "/service/user/get_user_info"));
    httpReq.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 3.监管 请求回来的http响应
    QNetworkReply* resp = m_httpClient.post(httpReq, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        // 3.1 http 层面的错误
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        // 3.2 获取传输过来的数据，进行反序列化
        QByteArray body = resp->readAll();
        im::GetUserInfoRsp rspObj;
        rspObj.deserialize(&m_serializer, body);

        // 3.3 判断业务上的错误
        if(!rspObj.success()){
            LOG() << "【获取个人信息】出错！ requestId=" << rspObj.requestId() << " error: " << rspObj.errmsg();
            resp->deleteLater();
            return ;
        }

        // 3.4 把响应数据，保存到dataCenter中
        m_dataCenter->resetMyself(rspObj);

        // 3.5 发送完成信号
        emit m_dataCenter->getMyselfDone();
        LOG() << "【获取个人信息】处理响应 requestId=" << rspObj.requestId();

        // 3.6 释放内存
        resp->deleteLater();
    });
}

void NetClient::getFriendList(const QString &loginSessionId)
{
    // 1.构造请求
    QNetworkRequest httpReq(QUrl(HTTP_URL + "/service/friend/get_friend_list"));
    httpReq.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    QByteArray body;
    im::GetFriendListReq friendPB;
    friendPB.setRequestId(makeRequestId());
    friendPB.setSessionId(loginSessionId);
    body = friendPB.serialize(&m_serializer);

    // 2.处理响应
    QNetworkReply* resp = m_httpClient.post(httpReq, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        // 2.1 http 层面的错误
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        // 2.2 处理数据，进行反序列化
        QByteArray body = resp->readAll();
        im::GetFriendListRsp respPB;
        respPB.deserialize(&m_serializer, body);

        // 2.3 判断业务上的错误
        if(!respPB.success()){
            LOG() << "【获取好友列表信息】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        // 2.4 拿到数据，进行赋值
        m_dataCenter->resetFriendList(respPB);

        // 2.5 发送信号
        emit m_dataCenter->getFriendListDone();
        LOG() << "【获取好友列表信息】处理响应 requestId=" << respPB.requestId();

        // 2.6 释放内存
        resp->deleteLater();
    });
}

void NetClient::getChatSessionList(const QString &loginSessionId)
{
    // 1. 创建请求
    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/get_chat_session_list"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2. 处理响应
    im::ChatSessionCreateReq repPB;
    repPB.setRequestId(makeRequestId());
    repPB.setSessionId(loginSessionId);
    QByteArray body = repPB.serialize(&m_serializer);
    QNetworkReply* resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        // 2.1 http内部错误
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        // 2.2 处理响应数据，进行反序列化
        QByteArray body = resp->readAll();
        im::GetChatSessionListRsp rspPB;
        rspPB.deserialize(&m_serializer, body);

        // 2.3 判断是否为业务上的错误
        if(!rspPB.success()){
            LOG() << "【获取好友列表信息】出错！ requestId=" << rspPB.requestId() << " error: " << rspPB.errmsg();
            resp->deleteLater();
            return ;
        }

        // 2.4 进行赋值+发信号
        m_dataCenter->resetChatSessionList(rspPB);
        emit m_dataCenter->getChatSessionListDone();
        LOG() << "【获取会话列表信息】处理响应 requestId=" << rspPB.requestId();

        // 2.5 内存释放
        resp->deleteLater();
    });

}

void NetClient::getApplyList(const QString &loginSessionId)
{
    // 1.创建请求
    im::GetPendingFriendEventListReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    QByteArray body = reqPB.serialize(&m_serializer);
    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/get_pending_friend_events"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    QNetworkReply* resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        // 2.1 http内部错误
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        // 2.2 处理响应数据
        QByteArray body = resp->readAll();
        im::GetPendingFriendEventListRsp respPB;
        respPB.deserialize(&m_serializer, body);

        // 2.3 判断是否为业务上的错误
        if(!respPB.success()){
            LOG() << "【获取好友申请列表】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        // 2.4 进行赋值+发信号
        m_dataCenter->resetApplyList(respPB);
        emit m_dataCenter->getApplyListDone();
        LOG() << "【获取好友申请列表信息】处理响应 requestId=" << respPB.requestId();

        // 2.5 内存释放
        resp->deleteLater();
    });
}

void NetClient::getRecentMsgList(const QString& loginSessionId, const QString& chatSessionId, bool isUI)
{
    // 构造请求
    QNetworkRequest req(QUrl(HTTP_URL + "/service/message_storage/get_recent"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");
    QByteArray body;
    im::GetRecentMsgReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setChatSessionId(chatSessionId);
    reqPB.setMsgCount(30);
    reqPB.setSessionId(loginSessionId);
    body = reqPB.serialize(&m_serializer);

    // 处理响应
    QNetworkReply* resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        // 2.1 http内部错误
        if(resp->error() != QNetworkReply::NoError){
           LOG() << "http通信出错：" << resp->errorString();
           resp->deleteLater();
           return ;
        }

        // 2.2处理响应的数据，进行反序列化
        im::GetRecentMsgRsp respPB;
        respPB.deserialize(&m_serializer, resp->readAll());

        // 2.3 判断是否为业务上的错误
        if(!respPB.success()){
           LOG() << "【获取最近消息列表】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
           resp->deleteLater();
           return ;
        }

        // 2.4 进行赋值+发信号
        m_dataCenter->resetRecentMsgList(chatSessionId, respPB);
        if(isUI){
            emit m_dataCenter->getRecentMsgListDone(chatSessionId);
        }else{
            emit m_dataCenter->getRecentMsgListDoneNoUI(chatSessionId);
        }
        LOG() << "【获取最近消息列表】处理响应 requestId=" << respPB.requestId()
              << ", sessionId=" << loginSessionId
              << ", chatSessionId=" << chatSessionId;
        // 2.5 内存释放
        resp->deleteLater();
    });
}

void NetClient::sendMessage(const QString &loginSessionId, const QString& chatSessionId,
                                model::MessageType type,const QByteArray &content, const QString& extraInfo)
{
    // 1.构造请求
    im::NewMessageReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setChatSessionId(chatSessionId);

    im::MessageContent msgContent;
    if(type == model::MessageType::TEXT_TYPE){
        msgContent.setMessageType(im::MessageTypeGadget::MessageType::STRING);
        im::StringMessageInfo stringInfo;
        stringInfo.setContent(QString(content));
        msgContent.setStringMessage(stringInfo);
    }else if(type == model::MessageType::IMAGE_TYPE){
        msgContent.setMessageType(im::MessageTypeGadget::MessageType::IMAGE);
        im::ImageMessageInfo imageInfo;
        imageInfo.setFileId("");
        imageInfo.setImageContent(content);
        msgContent.setImageMessage(imageInfo);
    }else if(type == model::MessageType::FILE_TYPE){
        msgContent.setMessageType(im::MessageTypeGadget::MessageType::FILE);
        im::FileMessageInfo fileInfo;
        fileInfo.setFileId("");
        fileInfo.setFileName(extraInfo);    // 额外信息一般用于文件名，也可以适当用于其他信息
        fileInfo.setFileContents(content);
        fileInfo.setFileSize(content.size());
        msgContent.setFileMessage(fileInfo);
    }else if(type == model::MessageType::SPEECH_TYPE){
        msgContent.setMessageType(im::MessageTypeGadget::MessageType::SPEECH);
        im::SpeechMessageInfo speechInfo;
        speechInfo.setFileId("");
        speechInfo.setFileContents(content);
        msgContent.setSpeechMessage(speechInfo);
    }else {
        LOG() << "未知的 MessageType! messageType=" << type;
        return;
    }
    reqPB.setMessage(msgContent);
    QNetworkRequest req(QUrl(HTTP_URL + "/service/message_transmit/new_message"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.解析响应
    QNetworkReply* resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::NewMessageRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【发送消息】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        // 发送信号更新数据
        emit m_dataCenter->sendMessageDone(type, content, extraInfo);
        LOG() << "【发送消息】处理响应 requestId=" << respPB.requestId();

        resp->deleteLater();
    });
}

void NetClient::changeNickName(const QString &loginSessionId, const QString &newNick)
{
    // 构造请求
    im::SetUserNicknameReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setNickname(newNick);
    QByteArray body = reqPB.serialize(&m_serializer);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/set_nickname"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送响应
    QNetworkReply* resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::NewMessageRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【发送消息】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetNickName(newNick);

        emit m_dataCenter->changeNickNameDone();
        LOG() << "【修改昵称】处理响应 requestId=" << respPB.requestId();

        resp->deleteLater();
    });
}

void NetClient::changeDescription(const QString &loginSessionId, const QString &description)
{
    // 构造请求
    im::SetUserDescriptionReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setDescription(description);
    QByteArray body = reqPB.serialize(&m_serializer);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/set_description"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送响应
    QNetworkReply* resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::SetUserDescriptionRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【发送消息】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetDescption(description);

        emit m_dataCenter->changeDescriptionDone();
        LOG() << "【修改签名】处理响应 requestId=" << respPB.requestId();

        resp->deleteLater();
    });
}

void NetClient::changeAvatar(const QString &loginSessionId, const QByteArray &imageByte)
{
    // 构造请求
    im::SetUserAvatarReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setAvatar(imageByte);
    QByteArray body = reqPB.serialize(&m_serializer);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/set_avatar"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送响应
    QNetworkReply* resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::SetUserAvatarRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【发送消息】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetAvatar(imageByte);

        emit m_dataCenter->changeAvatarDone();
        LOG() << "【修改头像】处理响应 requestId=" << respPB.requestId();

        resp->deleteLater();
    });
}

void NetClient::changePhone(const QString &loginSessionId, const QString &phoneToChange, const QString &codeId, const QString &code)
{
    im::SetUserPhoneNumberReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setPhoneNumber(phoneToChange);
    reqPB.setPhoneVerifyCodeId(codeId);
    reqPB.setPhoneVerifyCode(code);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/set_phone"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送请求
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::SetUserPhoneNumberRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【修改手机号】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetPhone(phoneToChange);
        LOG() << "修改的手机号：" << phoneToChange;

        emit m_dataCenter->changePhoneDone();

    });
}

void NetClient::getVerifyCode(const QString &phone)
{
    // 构造请求
    im::PhoneVerifyCodeReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setPhoneNumber(phone);
    QByteArray body = reqPB.serialize(&m_serializer);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/get_phone_verify_code"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送响应
    auto resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::PhoneVerifyCodeRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【发送验证码】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetVerifyCode(respPB.verifyCodeId());

        emit m_dataCenter->getVerifyCodeDone();
        LOG() << "【发送验证码】处理响应 requestId=" << respPB.requestId()
              << " 收到验证码id：" << respPB.verifyCodeId();

        resp->deleteLater();
    });
}

void NetClient::deleteFriend(const QString &loginSessionId, const QString &userId)
{
    // 构造请求
    im::FriendRemoveReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setPeerId(userId);
    QByteArray body = reqPB.serialize(&m_serializer);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/remove_friend"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送响应
    auto resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::FriendRemoveRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【删除好友】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->removeFriend(userId);

        emit m_dataCenter->deleteFriendDone();
        LOG() << "【发送验证码】处理响应 requestId=" << respPB.requestId()
              << " 删除好友的ID：" << userId;

        resp->deleteLater();
    });
}

void NetClient::addFriendApply(const QString& loginSessionId, const QString &userId)
{
    // 构造请求
    im::FriendAddReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setRespondentId(userId);
    QByteArray body = reqPB.serialize(&m_serializer);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/add_friend_apply"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 发送响应
    auto resp = m_httpClient.post(req, body);
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::FriendRemoveRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【好友申请】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        emit m_dataCenter->addFriendApplyDone();
        LOG() << "【发送验证码】处理响应 requestId=" << respPB.requestId()
              << " 添加好友的ID：" << userId;

        resp->deleteLater();
    });
}

void NetClient::acceptFriendApply(const QString& loginSessionId, const QString &userId)
{
    // 构造请求
    im::FriendAddProcessReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setNotifyEventId("");
    reqPB.setAgree(true);
    reqPB.setApplyUserId(userId);
    reqPB.setSessionId(loginSessionId);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/add_friend_process"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::FriendAddProcessRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【处理好友申请】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        // 同意请求
        // 1. 删除缓存中的申请对象 2.添加好友对象
        model::UserInfo userInfo = m_dataCenter->removeFromApplyList(userId);
        m_dataCenter->getFriendList()->push_front(userInfo);
        // m_dataCenter->getChatSessionList()->push_front(chatInfo);

        emit m_dataCenter->acceptFriendApplyDone();
        LOG() << "【同意好友申请】处理响应 requestId=" << respPB.requestId()
              << " 新好友的ID：" << userId;

        resp->deleteLater();
    });
}

void NetClient::createGroupChatSession(const QString &loginSessionId, const QList<QString> &member)
{
    // 构造请求
    im::ChatSessionCreateReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    QString groupName = QString("未命名(%1)").arg(member.size());
    reqPB.setChatSessionName(groupName);
    reqPB.setMemberIdList(member);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/create_chat_session"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::ChatSessionCreateRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【群创建】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }
        // 服务器会在创建会话完成后, 通过 ws 给会话中所有成员推送会话创建信息
        emit m_dataCenter->createGroupChatSessionDone();
        LOG() << "群信息发送成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });

}

void NetClient::getMemberList(const QString& loginSessionId, const QString &chatSessionId)
{
    // 构造请求数据
    im::GetChatSessionMemberReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setChatSessionId(chatSessionId);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/get_chat_session_member"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::GetChatSessionMemberRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【群成员列表获取】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetMemberList(chatSessionId, respPB.memberInfoList());

        emit m_dataCenter->getMemberListDone(chatSessionId);
        LOG() << "群成员列表获取发送成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });

}

void NetClient::searchUser(const QString& loginSessionId, const QString& searchKey)
{
    // 构造请求数据
    im::FriendSearchReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setSearchKey(searchKey);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/friend/search_friend"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::FriendSearchRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【用户搜索】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetSearchUserResult(respPB.userInfo());

        emit m_dataCenter->searchUserDone();
        LOG() << "用户搜索发送成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::searchMessage(const QString& loginSessionId, const QString &chatSessionId, const QString &searchKey)
{
    // 1.构造请求
    im::MsgSearchReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setChatSessionId(chatSessionId);
    reqPB.setSearchKey(searchKey);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/message_storage/search_history"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::MsgSearchRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【历史群消息获取】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetSearchMessageResult(respPB.msgList());

        emit m_dataCenter->searchMessageDone();
        LOG() << "历史群消息获取发送成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::searchMessageByTime(const QString& loginSessionId, const QString &chatSessionId,
                         const QDateTime &start, const QDateTime &end)
{
    // 1.构造请求
    im::GetHistoryMsgReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setChatSessionId(chatSessionId);
    reqPB.setSessionId(loginSessionId);
    reqPB.setStartTime(start.toSecsSinceEpoch());
    reqPB.setOverTime(end.toSecsSinceEpoch());

    QNetworkRequest req(QUrl(HTTP_URL + "/service/message_storage/get_history"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::GetHistoryMsgRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【历史群消息获取】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetSearchMessageResult(respPB.msgList());

        emit m_dataCenter->searchMessageDone();
        LOG() << "群成员列表获取发送成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::userLogin(const QString &username, const QString &password)
{
    // 1. 构造请求 body
    im::UserLoginReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setNickname(username);
    reqPB.setPassword(password);
    reqPB.setVerifyCodeId("");      // 验证码客户端验证即可，这里就不在设置
    reqPB.setVerifyCode("");

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/username_login"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            emit m_dataCenter->userLoginDone(false, resp->errorString());
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::UserLoginRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【用户登入】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            emit m_dataCenter->userLoginDone(false, respPB.errmsg());
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetLoginSessionId(respPB.loginSessionId());

        emit m_dataCenter->userLoginDone(true, "");
        LOG() << "用户登录成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::userRegister(const QString &username, const QString &password)
{
    // 1. 构造请求 body
    im::UserRegisterReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setNickname(username);
    reqPB.setPassword(password);
    reqPB.setVerifyCodeId("");      // 验证码客户端验证即可，这里就不在设置
    reqPB.setVerifyCode("");

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/username_register"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            emit m_dataCenter->userRegisterDone(false, resp->errorString());
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::UserRegisterRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【用户注册】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            emit m_dataCenter->userRegisterDone(false, respPB.errmsg());
            resp->deleteLater();
            return ;
        }

        emit m_dataCenter->userRegisterDone(true, "");
        LOG() << "用户注册成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::phoneLogin(const QString &phone, const QString &codeID, const QString &code)
{
    // 1. 构造请求 body
    im::PhoneLoginReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setPhoneNumber(phone);
    reqPB.setVerifyCodeId("");      // 验证码客户端验证即可，这里就不在设置
    reqPB.setVerifyCode("");

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/phone_login"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::PhoneLoginRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【手机号登入】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            emit m_dataCenter->phoneLoginDone(false, respPB.errmsg());
            resp->deleteLater();
            return ;
        }

        m_dataCenter->resetLoginSessionId(respPB.loginSessionId());

        emit m_dataCenter->phoneLoginDone(true, "");
        LOG() << "手机号登录成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });

}

void NetClient::phoneRegister(const QString &phone, const QString &codeID, const QString &code)
{
    // 1. 构造请求 body
    im::PhoneRegisterReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setPhoneNumber(phone);
    reqPB.setVerifyCodeId("");      // 验证码客户端验证即可，这里就不在设置
    reqPB.setVerifyCode("");

    QNetworkRequest req(QUrl(HTTP_URL + "/service/user/phone_register"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::PhoneRegisterRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【手机号注册】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            emit m_dataCenter->phoneRegisterDone(false, respPB.errmsg());
            resp->deleteLater();
            return ;
        }

        emit m_dataCenter->phoneRegisterDone(true, "");
        LOG() << "用户注册成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::getSingleFile(const QString &loginSessionId, const QString &fileID)
{
    // 1. 构造请求 body
    im::GetSingleFileReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setFileId(fileID);
    reqPB.setSessionId(loginSessionId);

    QNetworkRequest req(QUrl(HTTP_URL + "/service/file/get_single_file"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::GetSingleFileRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【从服务器上获取文件】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        // 获取到的结果数据，可能会很多，所以不保存在缓存中，从服务器上拿来之后直接展示到本地

        emit m_dataCenter->getSingleFileDone(fileID, respPB.fileData().fileContent());
        LOG() << "从服务器上获取文件成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}

void NetClient::speechConvertText(const QString &loginSessionId, const QString& fileId, const QByteArray& content)
{
    // 1.构造请求
    im::SpeechRecognitionReq reqPB;
    reqPB.setRequestId(makeRequestId());
    reqPB.setSessionId(loginSessionId);
    reqPB.setSpeechContent(content);
    // reqPB.setUserId();
    QNetworkRequest req(QUrl(HTTP_URL + "/service/speech/recognition"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    // 2.处理响应
    auto resp = m_httpClient.post(req, reqPB.serialize(&m_serializer));
    connect(resp, &QNetworkReply::finished, this, [=]{
        if(resp->error() != QNetworkReply::NoError){
            LOG() << "http通信出错：" << resp->errorString();
            resp->deleteLater();
            return ;
        }

        QByteArray body = resp->readAll();
        im::SpeechRecognitionRsp respPB;
        respPB.deserialize(&m_serializer, body);

        if(!respPB.success()){
            LOG() << "【从服务器上获取转换的文字】出错！ requestId=" << respPB.requestId() << " error: " << respPB.errmsg();
            resp->deleteLater();
            return ;
        }

        emit m_dataCenter->speechConvertTextDone(fileId, respPB.recognitionResult());
        LOG() << "从服务器上获取转换文字成功 " << "requestID:" << respPB.requestId();
        resp->deleteLater();
    });
}


const QString NetClient::makeRequestId()
{
    return "R" + QUuid::createUuid().toString().sliced(25, 12);
}

} // namespace network
